home *** CD-ROM | disk | FTP | other *** search
/ Scene World 20 / Scene_World_20_2013-01-04_People_of_Liberty_Scene_World_Magazine_Side_A.d64 / ! planetcode ! < prev    next >
Text File  |  2023-02-26  |  17KB  |  705 lines

  1. ;--------------------------------------
  2. ;Scene World - Issue #19
  3. ;Assembly Games Programming Tutorial #2
  4. ;
  5. ;Planet Popper - Part 1 - The basics
  6. ;By Richard Bayliss.
  7. ;
  8. ;--------------------------------------
  9.  
  10. ;This tutorial will get you started on
  11. ;how to create a simple shoot 'em up
  12. ;game. PLANET POPPER will show you
  13. ;examples of how to get sprites moving
  14. ;inside a loop. How the player can shoot
  15. ;and destroy the planets. As this is
  16. ;only the first example for the Planet
  17. ;Popper tutorial game. We will be taking
  18. ;a look at enhancing the game later on.
  19.  
  20. ;Those who are using ACME, uncomment
  21. ;the following command. As this will
  22. ;be your filename for your program.
  23. ;If you're using Turbo Assembler on a
  24. ;Commodore 64, leave this commented.
  25.  
  26.          ;!to "planetp1.prg",cbm
  27.  
  28. ;Okay, now to insert the music
  29. ;sprites files in Turbo Assembler,
  30. ;press the '_' and press SHIFT+L and
  31. ;enter the filename PLANETSPRITES. ACME
  32. ;cross assembler users, uncomment this
  33. ;to insert the sprites:
  34.  
  35.          ;* = $2000
  36.          ;!bin "planetsprites.prg",,2
  37.  
  38.  
  39. ;Right now, we want some variables to
  40. ;represent various features that will
  41. ;be used in our game source.
  42.  
  43.  
  44. playerx  = $3000 ;Player ship X position
  45. playery  = $3001 ;Player ship Y position
  46. bulletx  = $3002;Player laser X position
  47. bullety  = $3003;Player laser Y position
  48. planetpos = $3004 ;Planet positions
  49. allsprites = $3000 ;Mainly for default
  50.                  ;positioning of all
  51.                  ;sprites.
  52.  
  53. collision = $3010;Collision registry for
  54.                 ;the sprites
  55.  
  56. bulletfired = $301e ;This will indicate
  57.                   ;whether the bullet
  58.                   ;has been fired or not
  59.  
  60. playerisdead = $301f;Guess what that is?
  61.  
  62.  
  63. ;Now our variables have been set, let's
  64. ;start the programming of our game. I
  65. ;think $4000 (sys13684) should do quite
  66. ;nicely, as this will only be a short
  67. ;program. :)
  68.  
  69.          *= $4000  ;Remember this
  70. restart
  71.          sei       ;SEt Irq flag so no
  72.                    ;interrupts are in
  73.                    ;action.
  74.          lda #$00  ;Black screen and
  75.                    ;border.
  76.          sta $d020
  77.          sta $d021
  78.  
  79.          lda #$14  ;Default C64 charset
  80.          sta $d018 ;(For now)
  81.  
  82.          lda #$08  ;Screen multicolour
  83.          sta $d016 ;is off
  84.  
  85.          lda #$ff  ;All sprites enabled
  86.          sta $d015 ;and Multicolour is
  87.          sta $d01c ;Enabled as well
  88.  
  89.          lda #$00  ;We don't want
  90.          sta $d017 ;Expanded sprites
  91.          sta $d01d ;...
  92.          sta $d01b ;or them behind the
  93.                    ;background.
  94.  
  95.          lda #$0b  ;Sprite multicolour1
  96.          sta $d025
  97.          lda #$0d  ;Sprite multicolour2
  98.          sta $d026
  99.  
  100. ;Clear the screen by filling it with the
  101. ;spacebar characters.
  102.  
  103. fillspace ldx #$00
  104. filloop  lda #$20
  105.          sta $0400,x
  106.          sta $0500,x
  107.          sta $0600,x
  108.          sta $06e8,x
  109.          inx
  110.          bne filloop
  111.  
  112.  
  113. ;Initialise the variables that represent
  114. ;that the player is alive, bullet isn't
  115. ;fired and all enemies are alive.
  116.  
  117.          lda #$00
  118.          sta bulletfired
  119.          sta playerisdead
  120.          lda #$01
  121.          sta planet1d+1
  122.          sta planet2d+1
  123.          sta planet3d+1
  124.          sta planet4d+1
  125.          sta planet5d+1
  126.          sta planet6d+1
  127.  
  128.  
  129. ;Reposition all of the game sprites
  130. ;according to the table. We put this
  131. ;inside a loop and also inside the
  132. ;all sprites variable zero page ($02)
  133. ;as this will help us put all sprites
  134. ;in place. it will read the table using
  135. ;x and y positions. we use the hardware
  136. ;sprite positions later on in the main
  137. ;code.
  138.  
  139.  
  140.          ldx #$00
  141. posloop  lda startpos,x
  142.          sta allsprites,x
  143.          inx
  144.          cpx #$10
  145.          bne posloop
  146.  
  147. ;Let's initialize the sprite frames and
  148. ;colours to how they should be.
  149.  
  150.          ldx #$00
  151. makespr  lda frames,x
  152.          sta $07f8,x;Hardware spritetype
  153.                    ;in default VIC Bank
  154.          lda colours,x
  155.          sta $d027,x
  156.          inx
  157.          cpx #$08
  158.          bne makespr
  159.  
  160. ;Main initialised bits are done, now
  161. ;we initialise an interrupt to get all
  162. ;sprites moving, and things going the
  163. ;way we want them to go.
  164.  
  165.          lda #$7f
  166.          sta $dc0d ;CIA Interrupts on
  167.  
  168.          lda #<irq ;Low bit of IRQ flag
  169.          ldx #>irq ;Hi bit of IRQ flag
  170.          sta $0314 ;Store to interrupt
  171.          stx $0315 ;Yep, and here too.
  172.  
  173.          lda #$2e  ;Start of top raster
  174.          sta $d012 ;(Move this if you
  175.                    ;need to).
  176.          lda #$1b
  177.          sta $d011 ;Switch screen on
  178.  
  179.          lda #$01  ;Interrupt set
  180.          sta $d01a
  181.  
  182.          cli       ;Clear the IRQ flag
  183.  
  184. ;It is time to synchronise the game
  185. ;code to how it should work. So let's
  186. ;get it working.
  187.  
  188. gameloop lda #$00
  189.          sta gamesync
  190.          cmp gamesync
  191.          beq *-3
  192.  
  193.          jsr expmsb ;Expand MSB to full
  194.          jsr mvplan ;Move planets
  195.          jsr mvplr;Move player
  196.          jsr mvbull ;Move player bullet
  197.          jsr rdcoll ;Collision checks
  198.          jsr plan2bul;Planet to bullet
  199.          jsr plan2plr;Planet to player
  200.          jsr planoff ;Check if all off
  201.  
  202.          jmp gameloop
  203.  
  204. ;Expand the sprite MSB to full screen.
  205. ;We do this by placing the labels that
  206. ;indicate the sprite positions, into
  207. ;the actual hardware sprite positions.
  208. ;The use of $D010 expands the screen
  209. ;position for the sprites.
  210.  
  211. expmsb   ldx #$00
  212. exploop  lda allsprites+1,x ;Y position
  213.          sta $d001,x ;Store to hardware
  214.          lda allsprites,x  ;X position
  215.          asl a  ;ACME, use just ASL
  216.          ror $d010 ;Rotate MSB to right
  217.          sta $d000,x ;Store to hardware
  218.          inx      ;We increment twice
  219.          inx      ;else we get silly
  220.          cpx #$10 ;results
  221.          bne exploop
  222.          rts      ;End of subroutine
  223.  
  224. ;Move the planets across the screen
  225. ;using a loop, that will allow them
  226. ;to move a certain speed.
  227.  
  228. mvplan   ldx #$00
  229. moveloop lda planetpos,x
  230.          clc
  231.          adc speedtable,x
  232.          sta planetpos,x
  233.          inx
  234.          cpx #$0c
  235.          bne moveloop
  236.          rts
  237.  
  238. ;Now move the player using the joystick
  239. ;plugged into port 2. The player can
  240. ;only move left/right and shoot
  241.  
  242. mvplr    lda $dc00;read joystick port 2
  243.          lsr a;up    ;Read up - ignore
  244.          lsr a;down  ;Read down - ignore
  245.          lsr a;left  ;Read left - check
  246.          bcs joyright
  247.          lda playerx ;Read player x pos
  248.          sec         ;Subtract by the
  249.          sbc #$02 ;speed of the movement
  250.          cmp #$0c ;Unless at #$0c
  251.          bcs storepx ;Store player X-Pos
  252.          lda #$0c ;Player at very left
  253. storepx  sta playerx
  254.  
  255. ;We want to allow the player to be able
  256. ;to shoot a bullet, even if it is moving
  257. ;otherwise it won't look right. :)
  258.  
  259.          jmp pushfire
  260.  
  261. joyright lsr a    ;Read right - check
  262.          bcs pushfire
  263.          lda playerx ;Read player X-Pos
  264.          clc      ;Add by the
  265.          adc #$02 ;Speed of the movement
  266.          cmp #$a2 ;Unless at #$a2 where
  267.          bcc storepx2 ;the player stops
  268.          lda #$a2 ;Player at very right
  269. storepx2 sta playerx
  270.  
  271.  
  272. ;Read the fire button
  273.  
  274. pushfire lda $dc00
  275.          lsr a ;We call LSR 5 times, as
  276.          lsr a ;we check each direction
  277.          lsr a ;the fire button is
  278.          lsr a ;always the 5th check if
  279.          lsr a ;you try to read a
  280.                ;joystick
  281.          bcs ignore ;No joy read if no
  282.                    ;fire button
  283.  
  284. ;Unlike the movements of the player we
  285. ;make a check to see whether a bullet
  286. ;has already been fired. If it has then
  287. ;the bullet is active and we ignore
  288. ;positioning the bullet - otherwise it
  289. ;will look very odd indeed. ;)
  290.  
  291. checkbul lda bulletfired ;Read it ...
  292.          cmp #$01 ;If active ...
  293.          beq ignore   ;Ignore bullet
  294.  
  295. ;Since the bullet is not active or
  296. ;moving here, we shall reposition the
  297. ;bullet at exactly the same location as
  298. ;where the player lies. This makes fair
  299. ;shooting.
  300.  
  301.          lda playerx ;Read player X pos
  302.          sta bulletx ;Store bullet X pos
  303.          lda playery ;Read player Y pos
  304.          sta bullety ;Store bullet Y pos
  305.  
  306. ;Now because we only want the bullet to
  307. ;appear once until offset, we activate
  308. ;the logic switch to bulletfired.
  309.  
  310.          lda #$01
  311.          sta bulletfired
  312.  
  313. ignore   rts ;Terminate routine
  314.  
  315. ;This is our main routine which will
  316. ;fire the bullet upscreen, until it has
  317. ;reached the top border of the screen.
  318. ;We only want the bullet to go upwards
  319. ;being that this shooting game's meant
  320. ;to be like that :)
  321.  
  322. mvbull   lda bulletfired ;Check if the
  323.          cmp #$01        ;bullet is
  324.          beq mvbull2     ;active, else
  325.          rts             ;ignore it.
  326.  
  327. mvbull2  lda bullety ;Read Y pos of the
  328.          sec         ;player's bullet
  329.          sbc #$08    ;subtract by 6 for
  330.                      ;speed.
  331.          cmp #$20    ;Has the bullet
  332.                      ;left the top
  333.                      ;border?
  334.          bcs bullset  ;bullet still on
  335.  
  336. ;Assuming that the bullet reaches the
  337. ;top and left the raster position #$20
  338. ;we can stop the bullet from moving,
  339. ;simply by changing the value of #$00
  340. ;to bullet fired. So that the player is
  341. ;ready to shoot another bullet.
  342.  
  343.          lda #$00    ;Bullet inactive
  344.          sta bulletfired
  345.          rts
  346.  
  347. ;Else keep the bullet moving
  348.  
  349. bullset  sta bullety
  350.          rts
  351.  
  352. ;Now for something, a shooting game
  353. ;can't be without. Yes, that's right
  354. ;a collision register. To do the
  355. ;collision. We are using a software box
  356. ;sprite/sprite check. There are two
  357. ;types of collision you'll want. Either
  358. ;a player/enemy or a bullet/enemy type
  359. ;collision.
  360.  
  361.  
  362.          ;Start with storing values to
  363.          ;each top/bottom, left/right
  364.          ;position inside the boxed area
  365.  
  366.          ;It looks something like this
  367.  
  368.          ;              ^
  369.          ;           sec:
  370.          ;s          sbc:
  371.          ;b             :
  372.          ;c    sec      :      clc
  373.          ;  _--sbc------0------adc----
  374.          ;              :
  375.          ;a          clc:
  376.          ;d          adc:
  377.          ;c             :
  378.          ;              :
  379.  
  380.  
  381. rdcoll   lda playerx ;Read player's ypos
  382.          sec
  383.          sbc #$06  ;Subtract Y pos by 6
  384.          sta collision ;store check 1
  385.          clc
  386.          adc #$0c    ;Add Y pos by 12
  387.          sta collision+1 ;store check 2
  388.          lda playery ;Read player's xpos
  389.          sec
  390.          sbc #$0c    ;Subtract by 12
  391.          sta collision+2
  392.          clc
  393.          adc #$18    ;Add by 32
  394.          sta collision+3
  395.  
  396. ;Now read the bullet and store to
  397. ;the collision registry, as we have done
  398. ;before to the player's registry.
  399.  
  400.          lda bulletx
  401.          sec
  402.          sbc #$06
  403.          sta collision+4 ;Exactly the
  404.          clc             ;same method
  405.          adc #$0c
  406.          sta collision+5
  407.          lda bullety
  408.          sec
  409.          sbc #$0c
  410.          sta collision+6
  411.          clc
  412.          adc #$18
  413.          sta collision+7
  414.          rts
  415.  
  416. ;Check whether or not the enemy hits
  417. ;the player's bullet (or vice versa) as
  418. ;we want to show that a collision has
  419. ;been made. we do this check for each
  420. ;planet. using a loop is usually easier
  421. ;blended into the game.
  422.  
  423. plan2bul
  424.          ldx #$00        ;Read inside
  425. bcolloop lda planetpos,x  ;the co-ords
  426.          cmp collision+4   ;of the
  427.          bcc planetsok   ;collision
  428.          cmp collision+5 ;area, other-
  429.          bcs planetsok   ;wise there is
  430.          lda planetpos+1,x ;no collision
  431.  
  432.          cmp collision+6 ;(jump to
  433.          bcc planetsok   ;planetsok),
  434.          cmp collision+7 ;else planets
  435.          bcs planetsok   ;are hit.
  436.  
  437. ;The collision test has passed. The
  438. ;bullet has entered the collision area
  439. ;of the planet. So we now stop a chosen
  440. ;planet. Reset the bullet and stop the
  441. ;loop as well. Oh, and reactivate the
  442. ;ability for the player to shoot again.
  443.  
  444.          lda #$00        ;Of which
  445.          sta planetpos,x   ;planets
  446.          sta planetpos+1,x
  447.          sta bulletx
  448.          sta bullety
  449.          sta planet1d,x  ;The chosen
  450.                          ;direction
  451.          sta planet1d+1,x
  452.          sta bulletfired
  453.          rts
  454.  
  455. planetsok inx
  456.          inx
  457.          cpx #$0c
  458.          bne bcolloop
  459.          rts
  460.  
  461.  
  462. ;Now check whether or not the player's
  463. ;ship has been hit by the planets. If
  464. ;the player has been hit, then remove
  465. ;all sprites and display 'you're dead'
  466. ;on to the screen.
  467.  
  468. plan2plr ldx #$00
  469. colloop2 lda planetpos,x
  470.          cmp collision,x
  471.          bcc nokill
  472.          cmp collision+1,x
  473.          bcs nokill
  474.          lda planetpos+1,x
  475.          cmp collision+2,x
  476.          bcc nokill
  477.          cmp collision+3,x
  478.          bcs nokill
  479.          jmp iamdead
  480.  
  481. ;Collision has failed, as the planets
  482. ;are on the outside area, so we move on
  483. ;to the next planet inside the loop.
  484.  
  485. nokill   inx
  486.          inx
  487.          cpx #$0c ;Both X+Y positions
  488.                   ;per planet
  489.          bne colloop2 ;return to loop
  490.          rts
  491.  
  492. ;The player is dead, so now we just
  493. ;show the game over message - or similar
  494. ;and wait for the player to press SPACE
  495. ;BAR to try again.
  496.  
  497. iamdead  lda #$00
  498.          sta $d015 ;Clear all sprites
  499.  
  500.          ldx #$00
  501. deadloop lda deadtext,x  ;Check if text
  502.          cmp #$40        ;is higher than
  503.          bcc dontswap    ;character #$40
  504.          sec     ;then change to
  505.          sbc #$40        ;correct case.
  506. dontswap
  507.          sta $059c,x ;Screen char pos.
  508.          lda #$0a ;Light red text
  509.          sta $d99c,x;Screen char colour
  510.          inx
  511.          cpx #$0e
  512.          bne deadloop
  513.  
  514. ;Wait for the player to respond by
  515. ;pressing the spacebar. After the space
  516. ;bar has been pressed. We shall restart
  517. ;the game again.
  518.  
  519. waitspace lda $dc01 ;Read port 1 / keys
  520.          lsr a
  521.          lsr a
  522.          lsr a
  523.          lsr a
  524.          lsr a ;5x = Spacebar
  525.          bcs waitspace
  526.          jmp restart ;Restart game
  527.  
  528. ;Check if/not all planets are off screen
  529. ;if they are still moving then keep them
  530. ;on. Otherwise reset the planet's pos.
  531.  
  532. planoff  lda planet1d
  533.          cmp #$00
  534.          bne notoff
  535.          lda planet1d+1
  536.          cmp #$00
  537.          bne notoff
  538.          lda planet2d
  539.          cmp #$00
  540.          bne notoff
  541.          lda planet2d+1
  542.          cmp #$00
  543.          bne notoff
  544.          lda planet3d
  545.          cmp #$00
  546.          bne notoff
  547.          lda planet3d+1
  548.          cmp #$00
  549.          bne notoff
  550.          lda planet4d
  551.          cmp #$00
  552.          bne notoff
  553.          lda planet4d+1
  554.          cmp #$00
  555.          bne notoff
  556.          lda planet5d
  557.          cmp #$00
  558.          bne notoff
  559.          lda planet5d+1
  560.          cmp #$00
  561.          bne notoff
  562.          lda planet6d
  563.          cmp #$00
  564.          bne notoff
  565.          lda planet6d+1
  566.          cmp #$00
  567.          bne notoff
  568.  
  569. ;Reset the planet sprite's positions
  570. ;as we have done before and move them
  571. ;again.
  572.  
  573.          ldx #0
  574. resetpos lda startpos+4,x
  575.          sta planetpos,x
  576.          inx
  577.          cpx #$0c
  578.          bne resetpos
  579.          ldx #$00
  580. resetspd lda #$01
  581.          sta planet1d+1,x
  582.          inx
  583.          inx
  584.          cpx #$0c
  585.          bne resetspd
  586.  
  587.  
  588. notoff
  589.  
  590.          rts
  591.  
  592.  
  593.  
  594.  
  595.  
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603.  
  604.  
  605.  
  606.  
  607. ;This is our main IRQ interrupt to
  608. ;allow a more synchronised game to
  609. ;operate.
  610.  
  611.  
  612. irq      asl $d019 ;ACK interrupt
  613.  
  614.          lda $dc0d
  615.          sta $dd0d ;VIC CIA again
  616.  
  617.          lda #$fa  ;Bottom raster pos
  618.          sta $d012 ;
  619.  
  620.          inc gamesync ;Add 1 to the game
  621.                       ;sync mode
  622.  
  623.          pla          ;End of interruot
  624.          tay
  625.          pla
  626.          tax
  627.          pla
  628.          rti
  629.  
  630.  
  631.  
  632.  
  633.  
  634.  
  635. ;Sprite starting position X/Y tables.
  636. ;ACME users, change .byte to !byte as
  637. ;the pseudo's completely different to
  638. ;both assemblers. :)
  639.  
  640. startpos .byte $58,$e0 ;Player X/Y
  641.          .byte $00,$00 ;Bullet (Offset)
  642.          .byte $1c,$40 ;Planet 1 Left
  643.          .byte $30,$80 ;Planet 2 Left
  644.          .byte $4c,$c0 ;Planet 3 Left
  645.          .byte $70,$50 ;Planet 4 Right
  646.          .byte $8c,$10 ;Planet 5 Right
  647.          .byte $a0,$20 ;Planet 6 Right
  648.  
  649. ;Sprite colour table. Well, the sprites
  650. ;are in fact planets. So for now, let's
  651. ;make the planet sprites blue as main
  652. ;colour. Player ship can be white.
  653.  
  654. colours  .byte $01,$01,$06,$06
  655.          .byte $06,$06,$06,$06
  656.  
  657. ;Sprite object frames (Player, bullet
  658. ;and planets as those are all we have
  659. ;for this little example. No animation
  660. ;whatsoever. This will be for part 2
  661. ;where we jazz things up a bit.
  662.  
  663. frames   .byte $80,$81,$82,$82
  664.          .byte $82,$82,$82,$82
  665.  
  666. ;Enemy speed table. As we are going to
  667. ;move the sprite dwon the screen
  668. ;we will be using the speed table.
  669. ;The table will be marked
  670. ;as 0 if a planet has been popped.
  671.  
  672. speedtable
  673. planet1d .byte $00,$01;Planet 1 X / Y
  674. planet2d .byte $00,$01;Planet 2 X / Y
  675. planet3d .byte $00,$01;Planet 3 X / Y
  676. planet4d .byte $00,$01;Planet 4 X / Y
  677. planet5d .byte $00,$01;Planet 5 X / Y
  678. planet6d .byte $00,$01;Planet 6 X / Y
  679.  
  680. ;Synchronizer switch, so outside of the
  681. ;IRQ interrupt we get the code in sync.
  682.  
  683. gamesync .byte $00
  684.  
  685. ;The dead message ACME users, change
  686. ;this to !text instead. ;)
  687.  
  688. deadtext .text "you  are  dead!"
  689.  
  690. ;And there we have it, a simple game
  691. ;tutorial. It may take a while for you
  692. ;to get used to this code. But I'm sure
  693. ;that you'll get somewhere with it.
  694. ;
  695. ;NEXT ISSUE:
  696. ;
  697. ;We will be expanding this game a bit
  698. ;further, by adding some more control
  699. ;to the planets and also jazz things up
  700. ;more with a nice game background,
  701. ;animated sprites. Also we'll be adding
  702. ;a scoring system and sound to it.
  703. ;Stay tuned.
  704.  
  705.